package com.basic.business.common.vueLog;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import ch.qos.logback.classic.spi.ThrowableProxyUtil;
import ch.qos.logback.core.AppenderBase;
import com.basic.business.common.utils.SpringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

public class WebSocketLogAppender extends AppenderBase<ILoggingEvent> {

    private static final DateTimeFormatter TIME_FORMATTER =
            DateTimeFormatter.ofPattern("HH:mm:ss.SSS").withZone(ZoneId.systemDefault());

    @Resource
    private LogWebSocketHandler logWebSocketHandler;

    @Override
    protected void append(ILoggingEvent event) {
        if (logWebSocketHandler == null) {
            // 如果还没有注入，尝试从Spring上下文获取
            logWebSocketHandler = SpringUtils.getBean(LogWebSocketHandler.class);
        }

        // 构建完整的日志消息
        String formattedLog = formatLogEvent(event);
        logWebSocketHandler.sendLogToClients(formattedLog);
    }

    /**
     * 格式化日志事件为控制台输出格式
     */
    private String formatLogEvent(ILoggingEvent event) {
        // 1. 时间戳
        String timestamp = TIME_FORMATTER.format(Instant.ofEpochMilli(event.getTimeStamp()));

        // 2. 线程名
        String threadName = event.getThreadName();

        // 3. 日志级别 (右对齐5字符)
        String level = String.format("%-5s", event.getLevel().toString());

        // 4. Logger名 (简化包名)
        String loggerName = abbreviateLoggerName(event.getLoggerName());

        // 5. 方法名和行号
        String methodInfo = getMethodInfo(event);

        // 6. 日志消息
        String message = event.getFormattedMessage();

        // 7. 异常堆栈 (如果有)
        String throwableInfo = formatThrowable(event);

        // 8. MDC上下文信息 (可选)
        String mdcInfo = formatMDC(event);

        // 组合所有部分
        StringBuilder sb = new StringBuilder()
                .append(timestamp).append(" ")
                .append(level).append(" ")
                .append(loggerName).append(" - ");

        if (!methodInfo.isEmpty()) {
            sb.append(methodInfo).append(" - ");
        }

        sb.append(message);

        if (!throwableInfo.isEmpty()) {
            sb.append("\n").append(throwableInfo);
        }

        if (!mdcInfo.isEmpty()) {
            sb.append("\n").append(mdcInfo);
        }

        return sb.toString();
    }

    /**
     * 简化Logger包名 (保留最后两个包名)
     */
    private String abbreviateLoggerName(String loggerName) {
        if (loggerName == null || loggerName.isEmpty()) {
            return "";
        }

        String[] parts = loggerName.split("\\.");
        if (parts.length <= 2) {
            return loggerName;
        }

        return Arrays.stream(parts)
                .skip(parts.length - 2)
                .collect(Collectors.joining("."));
    }

    /**
     * 获取方法信息 (类名.方法名:行号)
     */
    private String getMethodInfo(ILoggingEvent event) {
        if (event.getCallerData() != null && event.getCallerData().length > 0) {
            StackTraceElement caller = event.getCallerData()[0];
            return String.format("[%s.%s:%d]",
                    caller.getClassName().substring(caller.getClassName().lastIndexOf('.') + 1),
                    caller.getMethodName(),
                    caller.getLineNumber());
        }
        return "";
    }

    /**
     * 格式化异常信息
     */
    private String formatThrowable(ILoggingEvent event) {
        IThrowableProxy throwableProxy = event.getThrowableProxy();
        if (throwableProxy == null) {
            return "";
        }

        try {
            // 官方推荐方法 - 需要 Logback >= 1.3.0
            return ThrowableProxyUtil.asString(throwableProxy);
        } catch (NoSuchMethodError e) {
            // 兼容老版本的回退方案
            return getFullStackTrace(throwableProxy);
        }
    }

    private String getFullStackTrace(IThrowableProxy throwableProxy) {
        StringBuilder sb = new StringBuilder();
        IThrowableProxy current = throwableProxy;

        while (current != null) {
            // 异常头信息
            sb.append(current.getClassName());
            if (current.getMessage() != null) {
                sb.append(": ").append(current.getMessage());
            }
            sb.append("\n");

            // 堆栈跟踪
            StackTraceElementProxy[] stackTrace = current.getStackTraceElementProxyArray();
            if (stackTrace != null) {
                for (StackTraceElementProxy step : stackTrace) {
                    sb.append("\tat ").append(step.getSTEAsString()).append("\n");
                }
            }

            // 处理被抑制的异常
            IThrowableProxy[] suppressed = current.getSuppressed();
            if (suppressed != null) {
                for (IThrowableProxy sup : suppressed) {
                    sb.append("\tSuppressed: ");
                    appendThrowableInfo(sb, sup, "\t");
                }
            }

            // 移动到下一个原因
            current = current.getCause();
            if (current != null) {
                sb.append("Caused by: ");
            }
        }

        return sb.toString();
    }

    private void appendThrowableInfo(StringBuilder sb, IThrowableProxy throwable, String prefix) {
        sb.append(throwable.getClassName());
        if (throwable.getMessage() != null) {
            sb.append(": ").append(throwable.getMessage());
        }
        sb.append("\n");

        StackTraceElementProxy[] stackTrace = throwable.getStackTraceElementProxyArray();
        if (stackTrace != null) {
            for (StackTraceElementProxy step : stackTrace) {
                sb.append(prefix).append("\tat ").append(step.getSTEAsString()).append("\n");
            }
        }

        IThrowableProxy[] suppressed = throwable.getSuppressed();
        if (suppressed != null) {
            for (IThrowableProxy sup : suppressed) {
                sb.append(prefix).append("\tSuppressed: ");
                appendThrowableInfo(sb, sup, prefix + "\t");
            }
        }

        if (throwable.getCause() != null) {
            sb.append(prefix).append("Caused by: ");
            appendThrowableInfo(sb, throwable.getCause(), prefix);
        }
    }

    /**
     * 格式化MDC上下文信息
     */
    private String formatMDC(ILoggingEvent event) {
        Map<String, String> mdc = event.getMDCPropertyMap();
        if (mdc == null || mdc.isEmpty()) {
            return "";
        }

        return mdc.entrySet().stream()
                .map(entry -> entry.getKey() + "=" + entry.getValue())
                .collect(Collectors.joining(", ", "[MDC: ", "]"));
    }
}

